package com.xique.door.biz.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageInfo;
import com.xique.common.core.domain.R;
import com.xique.common.core.utils.OrikaUtil;
import com.xique.common.core.utils.SecurityUtils;
import com.xique.common.core.utils.StringUtils;
import com.xique.common.core.web.domain.AjaxResult;
import com.xique.door.api.request.device.RemoteDeviceListRequest;
import com.xique.door.bean.domain.*;
import com.xique.door.bean.dto.DeviceBuildingInfoDTO;
import com.xique.door.bean.request.device.*;
import com.xique.door.bean.search.AccessDeviceListSearch;
import com.xique.door.bean.search.device.DeviceListSearch;
import com.xique.door.bean.validation.DeviceValidation;
import com.xique.door.bean.vo.device.DeviceDetailVO;
import com.xique.door.bean.vo.device.DeviceListVO;
import com.xique.door.biz.service.IBuildingDeviceBizService;
import com.xique.door.biz.service.IDeviceBizService;
import com.xique.door.biz.service.IDeviceUserBizService;
import com.xique.door.command.IDeviceBaseControlService;
import com.xique.door.constant.AccessCommandConstant;
import com.xique.door.device.command.AccessCommandHQService;
import com.xique.door.device.freeview.service.biz.FreeviewCommandBizService;
import com.xique.door.service.IAccessDeviceService;
import com.xique.door.service.IBuildHouseService;
import com.xique.door.service.IBuildingDeviceService;
import com.xique.door.service.estate.IEstateUserDeviceService;
import com.xique.system.api.RemoteSystemUserService;
import com.xique.system.api.dto.OperateDTO;
import com.xique.door.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author shd
 * @create 2022/1/25 10:24
 */
@Service
@Slf4j
public class DeviceBizServiceImpl implements IDeviceBizService {

    @Autowired
    private DeviceValidation deviceValidation;

    @Autowired
    private IAccessDeviceService deviceService;

    @Autowired
    private IBuildingDeviceBizService buildingDeviceBizService;

    @Autowired
    private AccessCommandHQService accessCommandHQService;

    @Autowired
    private IDeviceUserBizService deviceUserBizService;

    @Autowired
    private ICardAuthorizationService cardAuthorizationService;

    // 物业和设备关联的service层
    @Autowired
    private IEstateUserDeviceService iEstateUserDeviceService;

    // 广告和设备关联的service层
    @Autowired
    private IDDeviceAdvertService idDeviceAdvertService;

    @Autowired
    private FreeviewCommandBizService freeviewCommandBizService;

    @Autowired
    private IBuildHouseService buildHouseService;

    @Autowired
    private IBuildingDeviceService buildingDeviceService;

    @Autowired
    private IDeviceBaseControlService deviceBaseControlService;

    @Autowired
    private RemoteSystemUserService remoteSystemUserService;

    @Autowired
    private IUserDeviceService userDeviceService;

    @Autowired
    private IVisitorDeviceService visitorDeviceService;

    @Autowired
    private IDCardDeviceService cardDeviceService;

    @Override
    public AjaxResult getDeviceList(DeviceListRequest request) {
        AccessDevice search = OrikaUtil.convert(request, AccessDevice.class);
        search.setParkId(SecurityUtils.getParkId());
        List<AccessDevice> list = deviceService.selectAccessDeviceList(search);
        List<Long> userIds = list.stream().filter(e-> e.getUpdateUser()!=null).map(e -> e.getUpdateUser()).collect(Collectors.toList());
        if (!userIds.isEmpty()){
            R<List<OperateDTO>> operateList = remoteSystemUserService.getOperateList(StringUtils.join(userIds, ","));
            List<OperateDTO> data = operateList.getData();
            list.forEach(item -> {
                OperateDTO operateDTO = data.stream().filter(e -> e.getOperateId().equals(item.getUpdateUser())).findAny().orElse(null);
                if (operateDTO!=null){
                    item.setUpdateBy(operateDTO.getOperateName());
                }
            });
        }
        long total = new PageInfo(list).getTotal();
        Map<String, Object> map = new HashMap<>(2);
        map.put("list", OrikaUtil.converts(list, DeviceListVO.class));
        map.put("total", total);
        return AjaxResult.success(map);
    }

    @Override
    public AjaxResult getDeviceDetail(Long deviceId) {
        if (StringUtils.isNull(deviceId)) {
            return AjaxResult.error("id不能为空");
        }
        AccessDevice device = deviceService.selectAccessDeviceById(deviceId);
        if (StringUtils.isNull(device)) {
            return AjaxResult.error("未找到对应的设备");
        }
        DeviceDetailVO vo = OrikaUtil.convert(device, DeviceDetailVO.class);
        DeviceBuildingInfoDTO dto = buildingDeviceBizService.selectDeviceBuildingInfo(device.getForeignId(), device.getAccessType());
        BeanUtils.copyProperties(dto, vo);
        return AjaxResult.success(vo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public AjaxResult addDevice(DeviceAddRequest request) {
        request.setParkId(SecurityUtils.getParkId());
        AjaxResult result = deviceValidation.checkDeviceAddRequest(request);
        if (AjaxResult.isError(result)) {
            return result;
        }
        AccessDevice accessDevice = deviceService.selectAccessDeviceBySn(request.getDevSn());
        if (StringUtils.isNotNull(accessDevice)) {
            return AjaxResult.error("sn已存在，请重新输入");
        }
        AccessDevice device = OrikaUtil.convert(request, AccessDevice.class);
        device.setParkId(request.getParkId());
        device.setForeignId((StringUtils.isNotNull(request.getElevatorId()) ? request.getElevatorId() : (StringUtils.isNotNull(request.getBuildingId()) ? request.getBuildingId() : (StringUtils.isNotNull(request.getAreaId()) ? request.getAreaId() : request.getParkId()))));
        device.setDeviceNumber(device.getDevSn());
        int count = deviceService.insertAccessDevice(device);
        if (count <= 0) {
            return AjaxResult.error("添加失败");
        }
        boolean isSuccess = buildingDeviceBizService.insertBuildingDevice(device, device.getAccessType(), device.getForeignId());
        if (!isSuccess) {
            return AjaxResult.error("添加失败");
        }

        return AjaxResult.success("添加成功");
    }

    @Override
    public AjaxResult editDevice(DeviceEditRequest request) {
        AjaxResult result = deviceValidation.checkDeviceEditRequest(request);
        if (AjaxResult.isError(result)) {
            return result;
        }
        AccessDevice device = OrikaUtil.convert(request, AccessDevice.class);
        int count = deviceService.updateAccessDevice(device);
        if (count <= 0) {
            return AjaxResult.error("编辑失败");
        }
        return AjaxResult.success("编辑成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public AjaxResult deleteDevice(DeviceDeleteRequest request) {
        AccessDevice device = deviceService.selectAccessDeviceById(request.getId());
        String onlineStatus = device.getOnlineStatus();
        if (StringUtils.isNull(onlineStatus) || "offline".equals(onlineStatus)) {
            int count = deviceService.deleteAccessDeviceById(request.getId());
            if (count <= 0) {
                return AjaxResult.error("删除失败");
            }

            // 删除与设备绑定的人员
            deviceUserBizService.removeAllDeviceUsers(request);

            // 删除与设备绑定的卡片
            cardAuthorizationService.deleteAllDeviceCardList(request);

            // 删除与设备绑定的访客
            visitorDeviceService.deleteVisitorAuthorize(request);

            // 删除与设备绑定的楼栋
            buildingDeviceService.deleteBuildBuildingV1(request.getId());

            // 删除与设备绑定的物业人员
            iEstateUserDeviceService.deleteByUserId(request.getId());

            // 删除与设备绑定的广告信息
            idDeviceAdvertService.deleteDDeviceAvertDeviceById(request.getId());

            userDeviceService.deleteUserDeviceByDeviceId(request.getId());
            return AjaxResult.success("删除成功");
        }

        UserDevice search = new UserDevice();
        search.setDeviceId(request.getId());
        List<UserDevice> userDeviceList = userDeviceService.selectUserDeviceList(search);
        if (!CollectionUtils.isEmpty(userDeviceList)) {
            return AjaxResult.error("设备下有绑定用户，不可删除，请联系管理员");
        }

        CardDevice cardDevice = new CardDevice();
        cardDevice.setDeviceId(request.getId());
        List<CardDevice> cardList = cardDeviceService.selectDCardDeviceList(cardDevice);
        if (!CollectionUtils.isEmpty(cardList)) {
            return AjaxResult.error("设备下有绑定卡，不可删除，请联系管理员");
        }

        QueryWrapper<VisitorDevice> condition = new QueryWrapper<>();
        condition.eq("device_id", request.getId());
        List<VisitorDevice> visitorDeviceList = visitorDeviceService.list(condition);
        if (!CollectionUtils.isEmpty(visitorDeviceList)) {
            return AjaxResult.error("设备下有绑定访客，不可删除，请联系管理员");
        }

        int count = deviceService.deleteAccessDeviceById(request.getId());
        if (count <= 0) {
            return AjaxResult.error("删除失败");
        }

        userDeviceService.deleteUserDeviceByDeviceId(request.getId());

        return AjaxResult.success("删除成功");
    }

    @Override
    public AjaxResult changeStatus(DeviceChangeStatusRequest request) {
        AccessDevice device = OrikaUtil.convert(request, AccessDevice.class);
        int count = deviceService.updateAccessDevice(device);
        if (count <= 0) {
            return AjaxResult.error("修改状态失败");
        }
        return AjaxResult.success("修改状态成功");
    }

    @Override
    public AjaxResult reboot(String json) {
        String devSn = String.valueOf(JSONObject.parseObject(json).get("devSn"));
        AccessDevice search = new AccessDevice();
        search.setDevSn(devSn);
        List<AccessDevice> accessDevices = deviceService.selectAccessDeviceList(search);
        if (accessDevices.isEmpty() || accessDevices.size()>1){
            return AjaxResult.error("设备不存在");
        }
        AccessDevice accessDevice = accessDevices.get(0);
        if (accessDevice.getModel().equals(AccessCommandConstant.DeviceType.HQ)){
            accessCommandHQService.reboot(devSn);
        }
        if (accessDevice.getModel().equals(AccessCommandConstant.DeviceType.FREEVIEW_45)||accessDevice.getModel().equals(AccessCommandConstant.DeviceType.FREEVIEW_32)){
            freeviewCommandBizService.reboot(devSn);
        }
        return AjaxResult.success("重启指令已下发");
    }

    @Override
    public List<AccessDevice> selectDeviceByHouseIds(List<Long> houseIds) {
        List<BuildHouse> buildHouses = buildHouseService.selectBuildHouseByIds(houseIds);
        List<Long> buildingIds = buildHouses.stream().map(BuildHouse::getBuildingId).distinct().collect(Collectors.toList());
        BuildingDevice buildingDevice = new BuildingDevice();
        buildingDevice.setBuildingIds(buildingIds);
        List<BuildingDevice> buildingDevices = buildingDeviceService.selectBuildingDeviceList(buildingDevice);
        List<Long> deviceIds = buildingDevices.stream().map(BuildingDevice::getDeviceId).collect(Collectors.toList());
        List<AccessDevice> accessDevices = deviceService.selectAccessDeviceByIds(deviceIds);
        return accessDevices;
    }

    /**
     * @param parkId
     * @description: 查询车场下的所有设备
     * @author caogq
     * @date: 2022/3/5 9:53
     * @Param
     */
    @Override
    public AjaxResult getAllDevices(Long parkId) {
        AccessDevice accessDevice = new AccessDevice();
        accessDevice.setParkId(parkId);
        List<AccessDevice> accessDevices = deviceService.selectAccessDeviceList(accessDevice);
        return AjaxResult.success(accessDevices);
    }

    @Override
    public AjaxResult getDeviceList(Long id) {

        id = SecurityUtils.getParkId();

        if (StringUtils.isNull(id)) {
            return AjaxResult.error("请传入id信息");
        }

        AccessDeviceListSearch search = new AccessDeviceListSearch();
        search.setParkId(id);

        List<AccessDeviceV1> list = deviceService.selectAccessDeviceList(search);

        return AjaxResult.success(OrikaUtil.converts(list, DeviceListVO.class));
    }

    @Override
    public AjaxResult getDeviceListV1(RemoteDeviceListRequest request) {

        Map<String, Object> map = new HashMap<>(2);
        map.put("list", new ArrayList<>());
        map.put("total", 0);

        DeviceListSearch search = OrikaUtil.convert(request, DeviceListSearch.class);
        search.setParkId(request.getProjectId());
        IPage<AccessDeviceV1> page = deviceService.selectDeviceListV1(search);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return AjaxResult.success(map);
        }

        List<DeviceListVO> vos = OrikaUtil.converts(page.getRecords(), DeviceListVO.class);

        map.put("list", vos);
        map.put("total", page.getTotal());

        return AjaxResult.success(map);
    }

    @Override
    public AjaxResult openDoor(String devSn, Long userId) {
        AccessDevice search = new AccessDevice();
        search.setDevSn(devSn);
        List<AccessDevice> accessDeviceList = deviceService.selectAccessDeviceList(search);
        if(org.apache.commons.collections4.CollectionUtils.isEmpty(accessDeviceList)){
            return AjaxResult.error("没有设备");
        }
        AjaxResult result = deviceBaseControlService.openDoor(accessDeviceList.get(0), userId);
        return result;
    }
}
